package pl.szpadel.android.gadu;


import pl.szpadel.android.gadu.packets.BasePacket;
import pl.szpadel.android.gadu.packets.NewStatus80;
import pl.szpadel.android.gadu.packets.ReceivedPacket;
import pl.szpadel.android.gadu.packets.SendPacket;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.widget.Toast;

/** Service performing communication tasks */
public class CommunicationService extends Service {

	public static final String TAG = "AndroidGaduService";
	
	/// Communication thread
	private CommunicationThread mCommThread;
	
	/// Handler - an ITC device
	private Handler mHandler;
	
	private boolean mStarted = false; // prevents multiple starts

	
   @Override
    public void onCreate() {
	   mHandler = new Handler(); // from now on we are able to perform ITC
	   
	   App.createInstance(getApplicationContext());
	   App.getInstance().setCommunicationService(this);
	   AGLog.i(TAG, "Service created");
	   mCommThread = new CommunicationThread(this);
    }

    @Override
    public void onDestroy() {
    	AGLog.i(TAG, "Service destroyed");
    	App.getInstance().setCommunicationService(null);
    	
    	mCommThread.stopCommThread();
    }
	
    @Override
    public void onStart(Intent intent, int id) {
    	super.onStart(intent, id);
    	
    	// test config, launch 
    	if (!mStarted) {
        	AGLog.i(TAG, "Service starting... ");
        	
    		mCommThread.start();
    		mStarted = true;
    		
    		// configured?
    		Config config = App.getInstance().getConfig();
    		config.read(this);

    		Activity activity = App.getInstance().getActivity();
    		
    		// configured:
    		if (config.hasLoginDetails()) {
    			AGLog.d(TAG, "config has login details, ab;e to connect");
    			// with login details ask contact manager to load contacts
    			 App.getInstance().getContactInfoManager().loadContacts();
    			
    			// we may try to connect
	    		// try connecting
	    		if (config.getConnected()) {
	    			AGLog.d(TAG, "config demand connection, connecting!");
	    			reconnectNow();
	    			// notify all of status loaded from config
	    			App.getInstance().broadcastStatusChange(config.getStatus());
	    		} else {
	    			// open login dialog
            		if (activity != null) {
                		Intent loginIntent = new Intent(activity, LogonActivity.class);
                		loginIntent.putExtra(LogonActivity.EXTRA_LOGON_MESSAGE, R.string.msg_please_logon);
        	    		activity.startActivity(loginIntent);
            		}
	    		}
    		} else {
    			// open login window
        		if (activity != null) {
            		Intent loginIntent = new Intent(activity, LogonActivity.class);
            		loginIntent.putExtra(LogonActivity.EXTRA_LOGON_MESSAGE, R.string.msg_please_logon);
    	    		activity.startActivity(loginIntent);
        		}
    		}
    		
        	AGLog.i(TAG, "Service started");
    	} // mStarted
    }
    
    
    /// Executes code in UI thread
    public void sendToUiThread(Runnable runnable ){
    	assert(mHandler != null);
    	mHandler.post(runnable);
    }
    
    /////////////////////////////////////////////////////////
    // interface
    
    /// Handles packet
    /// Call in UI thread
    public void onPacket(ReceivedPacket packet) {
    	AGLog.d(TAG, "Handling packet in UI thread: " + packet);
    	App.getInstance().broadcastPacket(packet);
    	
    	// if disconnects us, just do it
    	if (packet.getType() == BasePacket.TYPE_DISCONNECT) {
    		AGLog.w(TAG, "Server disconnects us");
    		
    		// stop connecting
    		mCommThread.disconnect();
    		
    		// warn user
    		Activity activity = App.getInstance().getActivity();
    		if (activity != null) {
	    		Toast.makeText(activity, R.string.toast_disconnected_by_server, Toast.LENGTH_SHORT).show();
	    		Intent intent = new Intent(activity, LogonActivity.class);
	    		intent.putExtra(LogonActivity.EXTRA_LOGON_MESSAGE, R.string.msg_please_logon);
	
	    		activity.startActivity(intent);
    		} else {
    			// warn anyway
    			Toast.makeText(this, R.string.toast_disconnected_by_server, Toast.LENGTH_SHORT).show();
    		}
    		// NOTE config is left unchanged
    	}
    }
    
    /// Handles connection state change
    // call in UI thread
    public void onConnectionStateChange(ConnectionState state) {
    	AGLog.i(TAG, "connection state changed: " + state);
    	
    	App.getInstance().broadcastConnectionState(state);
    	
    	// login failed?
    	if (state.getReason() == ConnectionState.REASON_LOGIN_FAILED){
    		Activity activity = App.getInstance().getActivity();
    		if (activity != null) {
	    		Toast.makeText(activity, R.string.toast_logon_failed, Toast.LENGTH_SHORT).show();
	    		Intent intent = new Intent(activity, LogonActivity.class);
	    		intent.putExtra(LogonActivity.EXTRA_LOGON_MESSAGE, R.string.msg_logon_failed);
	
	    		activity.startActivity(intent);
    		}
    	}
    }
    
    /// Forces attempt of connection immediately
    /// Called from UI thread
    public void reconnectNow() {
    	AGLog.i(TAG, "recconect now");
    	
    	Config cfg = App.getInstance().getConfig();
    	cfg.setConnected(true);
    	cfg.write(this);
    	
    	// turn on notification icon
    	App.getInstance().getUserNotification().showOutgoing();

    	mCommThread.forceReconnect();
    }
    
    /// Send specific packet to server
    public void sendPacket(SendPacket packet) {
    	AGLog.i(TAG, "Sending packet: " + packet);
    	mCommThread.sendPacket(packet);
    }
    
    /// Disconnects
    public void disconnect() {
    	AGLog.i(TAG, "disconnecting");
    	
    	Config cfg = App.getInstance().getConfig();
    	cfg.setConnected(false);
    	cfg.write(this);
    	
    	// set status to 'disconnected'
    	Status status = new Status(Status.GG_STATUS_NOT_AVAIL_DESCR, cfg.getStatus().getDescription());
    	mCommThread.sendPacket(new NewStatus80(status));
    	mCommThread.disconnect();
    	
    	// turn off user notification
    	App.getInstance().getUserNotification().hideOutgoing();

    }
    
    /// Changes status
    public void setStatus(Status status) {
    	AGLog.i(TAG, "set status: " + status);

    	// write
    	Config cfg = App.getInstance().getConfig();
    	cfg.setStatus(status);
    	cfg.write(this);
    	
    	// actually send status to server (if connected)
    	mCommThread.sendPacket(new NewStatus80(status));
    	
    	// notify everyone
    	App.getInstance().broadcastStatusChange(status);
    }
    
    
    /////////////////////////////////////////////////////////
    // implementation
    
 	@Override
	public IBinder onBind(Intent arg0) {
		AGLog.i(TAG, "onBind");
		return null;
	}
    
   

}
